package com.xuecheng.order.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.result.BaseWxPayResult;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.xuecheng.api.agent.LearningApiAgent;
import com.xuecheng.api.order.model.pay.PayCodeUrlResult;
import com.xuecheng.common.domain.code.CommonErrorCode;
import com.xuecheng.common.enums.order.OrderDealStatusEnum;
import com.xuecheng.common.exception.ExceptionCast;
import com.xuecheng.common.util.StringUtil;
import com.xuecheng.order.common.constant.OrderErrorCode;
import com.xuecheng.order.entity.Orders;
import com.xuecheng.order.entity.Pay;
import com.xuecheng.order.mapper.PayMapper;
import com.xuecheng.order.service.OrdersService;
import com.xuecheng.order.service.PayService;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * <p>
 * 订单支付信息 服务实现类
 * </p>
 *
 * @author itcast
 */
@Slf4j
@Service
public class PayServiceImpl extends ServiceImpl<PayMapper, Pay> implements PayService {

    @Autowired
    private WxPayService wxPayService;
    @Autowired
    private OrdersService ordersService;
    @Autowired
    private LearningApiAgent learningApiAgent;


    /**
     * 处理 WX 支付平台支付结果消息
     *
     * @param xmlResultString
     */
    @Override
    @GlobalTransactional
    public void notifyPayResult(String xmlResultString) throws Exception {
        // 1.判断并解析wx通知内容
        //      保证wx支付是成功：returncode和resultcode为SUCCESS
        //      如果支付失败，无需完成订单服务的业务逻辑操作
        if (StringUtil.isBlank(xmlResultString)) {
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }

        WxPayOrderNotifyResult notifyResult = null;
        try {
            notifyResult = wxPayService.parseOrderNotifyResult(xmlResultString);
        } catch (WxPayException e) {
            log.error(OrderErrorCode.E_160018.getDesc() + " : errMsg {}", e.getMessage());
            ExceptionCast.cast(OrderErrorCode.E_160018);
        }

        String returnCode = notifyResult.getReturnCode();
        String resultCode = notifyResult.getResultCode();

        String outTradeNo = notifyResult.getOutTradeNo();

        // 支付通知成功
        if (PayCodeUrlResult.WX_PAY_SUCCESS_FLAG.equalsIgnoreCase(returnCode) &&
                PayCodeUrlResult.WX_PAY_SUCCESS_FLAG.equalsIgnoreCase(resultCode)
        ) {


            //  2.修改订单状态
            //      完成消息幂等（wx支付平台会重复发消息）
            //          判断订单是否已经支付
            //              通过订单编号：out_trade_no
            LambdaQueryWrapper<Orders> ordersQueryWrapper = new LambdaQueryWrapper<>();
            // 创建订单没有支付的查询条件
            ordersQueryWrapper.eq(Orders::getOrderNo, outTradeNo);
            ordersQueryWrapper.eq(Orders::getStatus, new Integer(OrderDealStatusEnum.ORDER_DEAL_INIT_STATUS.getCode()));

            int count = ordersService.count(ordersQueryWrapper);

            if (count < 1) {
                log.error("订单信息不是初始态，订单编号：{}", outTradeNo);
                return;
            }

            //      订单数据：status
            //          判断订单是否存在
            //          判断订单的状态：支付前状态必须初始态
            //          修改内容：
            //              status
            LambdaUpdateWrapper<Orders> ordersUpdateWrapper = new LambdaUpdateWrapper<>();
            ordersUpdateWrapper.set(Orders::getStatus, new Integer(OrderDealStatusEnum.ORDER_DEAL_PAID_STATUS.getCode()));
            ordersUpdateWrapper.set(Orders::getChangeDate, LocalDateTime.now());
            ordersUpdateWrapper.eq(Orders::getOrderNo, outTradeNo);

            boolean orderResult = ordersService.update(ordersUpdateWrapper);

            // 如果业务数据操作失败，需要让wx支付平台继续通知，继续通知的方式是业务层对外抛出异常
            if (!orderResult) {
                ExceptionCast.cast(OrderErrorCode.E_160015);
            }
            //      订单支付数据：支付后的结果
            //          判断订单支付是否存在
            //          判断订单支付的状态：status 0
            //          修改内容：
            //              status
            //              pay_number
            //              pay_date
            //              receipt_amount
            //              buyer_pay_amount
            //              pay_response
            ordersQueryWrapper = new LambdaQueryWrapper<>();
            ordersQueryWrapper.eq(Orders::getOrderNo, outTradeNo);

            Orders orders = ordersService.getOne(ordersQueryWrapper);

            LambdaQueryWrapper<Pay> payQueryWrapper = new LambdaQueryWrapper<>();
            payQueryWrapper.eq(Pay::getOrderId, orders.getId());
            payQueryWrapper.eq(Pay::getStatus, PayCodeUrlResult.NOT_PAY);

            Pay pay = this.getOne(payQueryWrapper);
            if (ObjectUtils.isEmpty(pay)) {
                log.error("订单支付信息不是未支付，订单编号：{}", outTradeNo);
                return ;
            }
            pay.setStatus(PayCodeUrlResult.PAIED);
            // 记录wx的支付编号
            pay.setPayNumber(notifyResult.getTransactionId());
            // 记录wx支付平台的用户支付时间
            String timeEnd = notifyResult.getTimeEnd();
            DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
            LocalDateTime payTime = LocalDateTime.parse(timeEnd, dateTimeFormatter);

            pay.setPayDate(payTime);

            Integer settlementTotalFee = notifyResult.getSettlementTotalFee();
            if (!(ObjectUtils.isEmpty(settlementTotalFee))) {
                String settlementTotalFeeString = BaseWxPayResult.fenToYuan(settlementTotalFee);
                pay.setReceiptAmount(new BigDecimal(settlementTotalFeeString));
            }


            Integer cashFee = notifyResult.getCashFee();
            if (!(ObjectUtils.isEmpty(cashFee))) {
                String cashFeeString = BaseWxPayResult.fenToYuan(cashFee);
                pay.setBuyerPayAmount(new BigDecimal(cashFeeString));
            }

            pay.setPayResponse(xmlResultString);

            boolean payResult = this.updateById(pay);
            if (!payResult) {
                ExceptionCast.cast(OrderErrorCode.E_160017);
            }


            //  3.给用户支付后的内容创建一个默认的学习记录
            //      在学习中心完成：Feign远程调用
            learningApiAgent.createCourseRecord4S(orders.getUserName(), orders.getCoursePubId());


            // 支付通知失败
        } else {
            log.error("支付通过内容失败，订单编号：{}", outTradeNo);
        }


    }
}
